Skip to content

Add Startup settings: auto-connect to a host, open a new chat, last chat or terminal - #66

Merged
biraj21 merged 24 commits into
shellular-org:devfrom
jankarres:jan/startup-behaviour
Aug 20, 2026
Merged

Add Startup settings: auto-connect to a host, open a new chat, last chat or terminal#66
biraj21 merged 24 commits into
shellular-org:devfrom
jankarres:jan/startup-behaviour

Conversation

@jankarres

@jankarres jankarres commented Aug 19, 2026

Copy link
Copy Markdown

Getting from the app icon to a usable chat costs six taps and about seventeen seconds on every cold launch, and this brings it to zero for anyone who wants that. It adds a Startup section to "Settings" that decides two things about a launch: which host to connect to, and what to open once connected. Closes #62.

Both default to what the app does today, so nothing changes for anyone who does not open the page.

01-settings-startup-default

Switch auto-connect on and the second group wakes up. Agent and project appear only for the targets that need them.

03-settings-rule-configured

The result, with Last used host plus New chat. Zero taps, where it used to be six.

cold-start.mp4

How it is put together

  • lib/settings.ts gets a startup group next to server, editor and terminal, same defaults-plus-normalizer shape. That also handles migration, since an old settings file just gets the defaults filled in on the next read.
  • lib/startupPlan.ts is the whole decision, pure and unit tested: settings plus live state in, a plan out. No I/O.
  • state/startup.ts runs the sequence, connect, wait, resolve, open, with a cancel check at every await and a module-level hasRun so it can only ever fire on a cold start.
  • components/StartupRunner.tsx renders null and just starts the thing. It sits in App.tsx rather than inside the provider, because the provider also wraps onboarding and the rule must not fire during first run.
  • components/StartupBanner.tsx is the visible half, rendered by the Home tab in the slot OfflineBanner already uses.
  • lib/navigate.tsx pulls the chat, sessions, git client, system monitor and ports pushes out of the seven components that each had a copy. The chat push alone carries eleven props, and I did not want the startup path to become one more place they have to stay in sync.

Behaviour worth calling out

04-banner-connecting

The strip is cancellable, and leaving the Home tab cancels it too, since TabView unmounts the tab and the cleanup runs. That came free and is the behaviour you want anyway.

If the target cannot be reached, the app stays on Home and says why once. No fallback chain: opening a new chat because the last one is missing would be worse than doing nothing.

06-target-unreachable-toast

pickResumableSession sorts by updatedAt client-side rather than trusting the order the host sends. For a list a wrong order is cosmetic, but for "open the newest chat" it would quietly open the wrong conversation.

Two small things the navigate extraction changes rather than preserves. providerName now falls back from agent.title to agent.name before the raw id, where two of the old copies used the title alone and rendered an empty subtitle if a host reported none. And the ports page in the "More" tab is loaded dynamically now like every other page, because a static import inside lib/navigate.tsx would drag four pages into the initial bundle.

Testing

pnpm typecheck and pnpm format clean. pnpm test is 116 tests, up from 97, the new ones all on startupPlan. The production browser build compiles.

Ran end to end on the browser target against a real CLI host: each connect mode, the cold start above, cancel during connect, a tab switch mid-sequence, and both failure paths. Untested on Android and iOS, I did not set up the mobile build toolchain for this.

Before you merge

Two decisions you may see differently. Startup got its own settings category because it carries seven controls and governs the whole app rather than one surface, and the rule is global rather than per host, on the assumption that a phone tends to point at the same machine. Both are cheap to change.

If anything here should be different, conceptually or in the code, tell me and I will take care of it. Same if you would rather have it in smaller pieces: auto-connect with the Home target first, then lib/navigate.tsx and the five remaining targets.

biraj21 and others added 23 commits June 15, 2026 19:11
* feat: show CLI version and update status

* feat: add shift to terminal keyboard toolbar & update terminal input handling

* feat: add Reach Out page and integrate with About and More tabs

* feat: enhance in-app browser's new tab page

Kevin (a user) said that he didn't "feel" that he opened a browser when he went to our in-app browser.

* feat: enhance EmptyState with description across multiple tabs

* feat: simplify bookmarked sessions state management

* feat: add isSettledSessionStatus function & FIX permission handling in ChatConversationPage

* chore: v0.0.29
v0.0.38: Merge pull request shellular-org#47 from shellular-org/biraj/session-msgs-reverse-…
fix(v0.0.39): create chat sessions lazily on first message (shellular-org#50)
* Biraj/fixes (shellular-org#52)

* fix(chat): preserve draft config picks and pass them at session create

A draft chat has no ACP session, so mode/model picks made before the
first send were kept in local state and replayed afterwards. Two gaps
made them get lost or apply late:

- The draft effect reset configOptions from the host-cached agent config
  on every run, clobbering picks the user had already made. Skip the
  reset while pending changes exist.
- Agent metadata is only loaded on connection, so a draft opened after
  another chat populated the CLI's config cache rendered a stale
  toolbar. Refresh agents once per draft.

Also send configOptions with AI_SESSION_CREATE so the first turn starts
with the chosen config instead of the agent default, and bump
@shellular/protocol to 0.0.31 for the field.

* fix: re-use ticket on re-connects for speed

* fix: new chat prompt should not get cleared on reconnect

* fix(chat): stop selection jumping and copy burying the answer

Two issues reported on Android with a long OpenCode response:

Selecting text and dragging down jumped the selection to the top of the
conversation. A selection drag is auto-scrolled by the WebView, which
fires `scroll` but not `wheel`/`touchmove` — the events wired to
scroll-intent — so the top sentinel came into view, prepended ~30 older
messages, and corrected scrollTop out from under the drag. Suppress
load-more, auto-scroll, and stick-to-bottom while a selection is active
in the transcript.

Copying a response also copied the reasoning and every tool call with
its full JSON input/output, burying the actual answer. The message copy
button now emits only the answer; each folded section (reasoning, tool
call, tool-call group, command) carries its own copy button, so nothing
became unreachable.

* feat: Add git tree view for changes (shellular-org#46)

* feat: git tree view for changes

* chore: update diffs & increment version

---------

Co-authored-by: Biraj <biraj.pub@gmail.com>

---------

Co-authored-by: Raunak Raj <71929976+bajrangCoder@users.noreply.github.com>
v0.0.41: prompt queue & check git changes from chat page
@jankarres
jankarres force-pushed the jan/startup-behaviour branch from 92e7b1c to 995abf2 Compare August 19, 2026 09:25
@biraj21
biraj21 changed the base branch from main to dev August 20, 2026 18:07
@biraj21
biraj21 merged commit 92b7ad3 into shellular-org:dev Aug 20, 2026
@biraj21

biraj21 commented Aug 20, 2026

Copy link
Copy Markdown
Member

merged! thanks @jankarres :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auto-connect to a host on startup and open a new chat, the last chat or a terminal

2 participants